package com.stp.rabbitmq.listener;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.IoUtil;

import com.rabbitmq.client.Channel;
import com.stp.rabbitmq.config.ShardingFileConfig;
import com.stp.rabbitmq.entity.FileInfoEntity;
import com.stp.rabbitmq.entity.MessageEntity;
import org.apache.tomcat.jni.FileInfo;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component
public class ShardingFileRabbitmqListener {

    // 文件信息存储Map
    Map<String, FileInfoEntity> map = new HashMap<>();

    @RabbitListener(queues = {ShardingFileConfig.SHARDING_FILE_QUEUE})
    public void receiveMsg(Message message, Channel channel) throws Exception {

        MessageEntity msg = Convert.convert(MessageEntity.class, message.getBody());
        String uuid = msg.getUuid();

        // 处理首块分片
        if (!map.containsKey(uuid)) {
            String tmpdirPath = System.getProperty("java.io.tmpdir");
            String dateStr = new SimpleDateFormat("yyyyMMdd").format(new Date());
            String[] params = {tmpdirPath.substring(0, tmpdirPath.length() - 1), "tmpFile", dateStr, uuid};
            String fileUrl = String.join(File.separator, Arrays.asList(params));
            if (!new File(fileUrl).exists()) {
                new File(fileUrl).mkdirs();
            }
            String filePath = fileUrl + File.separator + msg.getFilename();
            new File(filePath).createNewFile();
            FileInfoEntity fileInfo = new FileInfoEntity();
            fileInfo.setNumber(0);
            fileInfo.setFilePath(filePath);
            map.put(uuid, fileInfo);
        }

        // 接收分片
        FileInfoEntity fileInfo = map.get(uuid);
        //第一步 打开将要写入的文件
        RandomAccessFile raf = new RandomAccessFile(fileInfo.getFilePath(), "rw");
        //第二步 打开通道
        try {
            FileChannel fileChannel = raf.getChannel();
            //第三步 计算偏移量
            long position = (msg.getChunkNumber() - 1) * msg.getChunkSize();
            //第四步 获取分片数据
            byte[] fileData = msg.getBody();
            //第五步 写入数据
            fileChannel.position(position);
            fileChannel.write(ByteBuffer.wrap(fileData));
            fileChannel.force(true);
            fileChannel.close();
            fileInfo.setNumber(fileInfo.getNumber() + 1);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            IoUtil.close(raf);
        }

        // 判断分片是否接收完成
        if (msg.getTotalChunks() == map.get(uuid).getNumber()) {
            // 文件接收完成
            System.out.println("接收文件全路径：" + fileInfo.getFilePath());
            // 移除map中文件信息
            map.remove(uuid);
        }
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }
}
